package com.umakr.ax.app.web;


import com.umakr.ax.app.service.MsgWebService;
import com.umakr.ax.core.base.AbstractController;
import com.umakr.ax.utils.DateUtil;
import com.umakr.ax.wechat.util.AddSha1;
import com.umakr.ax.wechat.util.JwThirdApix;
import com.umakr.ax.wechat.util.SpeedStorage;
import com.umakr.ax.wechat.util.OconvertUtils;
import com.umakr.ax.wechat.vo.WeixinOpenAccountEntity;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jeewx.api.core.exception.WexinReqException;
import org.jeewx.api.mp.aes.AesException;
import org.jeewx.api.mp.aes.WXBizMsgCrypt;
import org.jeewx.api.third.JwThirdAPI;
import org.jeewx.api.third.model.*;
import org.jeewx.api.wxuser.user.JwUserAPI;
import org.jeewx.api.wxuser.user.model.Wxuser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
 * 微信公众号第三方平台全网发布
 *
 * @author Wmdz
 * @since 2018-01-03
 */
@Controller
@RequestMapping("/api/web/openwx")
public class OpenwxController extends AbstractController {

    @Autowired
    Environment env;

    @Autowired
    MsgWebService msgWebService;

    /**
     *优码客公众号appid"wx39cd0a0d3bac11ea"//全网发布测试appid"wx570bc396a51b8ff8"
     */
    private final String APPID = "wx570bc396a51b8ff8";
    /**
     *AppID
     */
    private final static String COMPONENT_APPID = "wxc92172aa9f766406";
    /**
     *AppSecret
     */
    private final static String COMPONENT_APPSECRET = "ce055e1f4000b124c97127d32563bca3";
    /**
     *公众号消息加解密Key
     */
    private final static String COMPONENT_ENCODINGAESKEY = "umk1234567890123456789012345678901234567890";
    /**
     *公众号消息校验Token
     */
    private final static String COMPONENT_TOKEN = "umk1234567890123456789012345678901234567890";


    private static String EVENT_STRING = "event";
    private static String TEXT_STRING = "text";
    private static String IMAGE_STRING = "image";
    private static String LOCATION_STRING = "location";
    private static String VOICE_STRING = "voice";
    private static String TESTCOMPONENT_MSG_TYPE_TEXT_STRING = "TESTCOMPONENT_MSG_TYPE_TEXT";
    private static String QUERY_AUTH_CODE_STRING = "QUERY_AUTH_CODE";

    /**
     * 一键授权功能
     * @param request
     * @param response
     * @throws IOException
     * @throws AesException
     * @throws DocumentException
     */
    @RequestMapping(value = "/goAuthor")
    public void goAuthor(HttpServletRequest request, HttpServletResponse response) throws IOException, AesException, DocumentException {
        try {
            ApiComponentToken apiComponentToken = new ApiComponentToken();
            apiComponentToken.setComponent_appid(COMPONENT_APPID);
            apiComponentToken.setComponent_appsecret(COMPONENT_APPSECRET);
            WeixinOpenAccountEntity entity = getWeixinOpenAccount(COMPONENT_APPID);
            apiComponentToken.setComponent_verify_ticket(entity.getTicket());
            String componentAccessToken = JwThirdAPI.getAccessToken(apiComponentToken);
            //预授权码
            String wechatOpenDomain = env.getProperty("wechat.open.domain");
            String preAuthCode = JwThirdAPI.getPreAuthCode(COMPONENT_APPID, componentAccessToken);
            String url = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=" + COMPONENT_APPID + "&pre_auth_code=" + preAuthCode + "&redirect_uri=" + wechatOpenDomain + "/api/web/openwx/authorCallback&auth_type=1";
            logger.info(url);
            response.sendRedirect(url);
        } catch (WexinReqException e) {
            e.printStackTrace();
        }

    }

    /**
     * 授权后回调
     *
     * @param request
     * @param response
     * @throws IOException
     * @throws AesException
     * @throws DocumentException
     */
    @RequestMapping(value = "/authorCallback")
    public void authorCallback(HttpServletRequest request, HttpServletResponse response) throws IOException, AesException, DocumentException, WexinReqException {
        String authCode = request.getParameter("auth_code");
        String expiresIn = request.getParameter("expires_in");
        logger.info("auth_code : " + authCode);
        logger.info("expires_in : " + expiresIn);
        // 输出响应的内容。
        output(response, "auth_code : " + authCode + " expires_in : " + expiresIn);
        //auth_code : queryauthcode@@@O1jY7Ays6Ob2AFPRb8EJQ2aiYcVUffNNVTjSxWmiKyoPVTqOurnrVMP_PO6w47gx6K5dE7cH2USsuFsZZQXc-Q expires_in : 3600
        //TODO 绑定电台信息和公众号信息 appid 原始id

        ApiComponentToken apiComponentToken = new ApiComponentToken();
        apiComponentToken.setComponent_appid(COMPONENT_APPID);
        apiComponentToken.setComponent_appsecret(COMPONENT_APPSECRET);
        WeixinOpenAccountEntity entity = getWeixinOpenAccount(COMPONENT_APPID);
        apiComponentToken.setComponent_verify_ticket(entity.getTicket());
        String componentAccessToken = JwThirdAPI.getAccessToken(apiComponentToken);
        System.out.println("获取component_access_token = " + componentAccessToken);

        JSONObject authorizationInfoJson = JwThirdAPI.getApiQueryAuthInfo(COMPONENT_APPID, authCode, componentAccessToken);
        System.out.println("获取authorizationInfoJson = " + authorizationInfoJson);

        JSONObject authorizationInfo = authorizationInfoJson.getJSONObject("authorization_info");
        String authorizerAppid = authorizationInfo.getString("authorizer_appid");
        String authorizerAccessToken = authorizationInfo.getString("authorizer_access_token");
        String authorizerExpiresIn = authorizationInfo.getString("expires_in");
        String authorizerRefreshToken = authorizationInfo.getString("authorizer_refresh_token");
        System.out.println("获取authorizer_appid = " + authorizerAppid);
        System.out.println("获取authorizer_access_token = " + authorizerAccessToken);
        System.out.println("获取authorizer_expires_in = " + authorizerExpiresIn);
        System.out.println("获取authorizer_refresh_token = " + authorizerRefreshToken);

        ApiGetAuthorizer apiGetAuthorizer = new ApiGetAuthorizer();
        apiGetAuthorizer.setAuthorizer_appid(authorizerAppid);
        apiGetAuthorizer.setComponent_appid(COMPONENT_APPID);
        ApiGetAuthorizerRet apiGetAuthorizerRet = JwThirdAPI.apiGetAuthorizerInfo(apiGetAuthorizer, componentAccessToken);
        System.out.println("获取apiGetAuthorizerRet = " + apiGetAuthorizerRet);
        String userName = apiGetAuthorizerRet.getAuthorizer_info().getUser_name();

        System.out.println("获取user_name = " + userName);

        SpeedStorage.save("auth_code" + authorizerAppid, authCode);
        SpeedStorage.save("authorizer_access_token" + userName, authorizerAccessToken);
        SpeedStorage.save("authorizer_refresh_token" + authorizerAppid, authorizerRefreshToken);
    }






    /**
     * 授权事件接收
     * 第一步
     * @param request
     * @param response
     * @throws IOException
     * @throws AesException
     * @throws DocumentException
     */
    @RequestMapping(value = "/event/authorize")
    public void acceptAuthorizeEvent(HttpServletRequest request, HttpServletResponse response) throws IOException, AesException, DocumentException, WexinReqException {
        logger.info("微信第三方平台---------微信推送Ticket消息10分钟一次-----------" + DateUtil.getDateTime());
        //微信第三方平台---------微信推送Ticket消息10分钟一次-----------2018-01-06 12:26:29
        //微信第三方平台---------微信推送Ticket消息10分钟一次-----------2018-01-06 11:56:07

        processAuthorizeEvent(request);

        //TODO 暂时放到这里 2个小时内要重新获取
        ApiComponentToken apiComponentToken = new ApiComponentToken();
        apiComponentToken.setComponent_appid(COMPONENT_APPID);
        apiComponentToken.setComponent_appsecret(COMPONENT_APPSECRET);
        WeixinOpenAccountEntity entity = getWeixinOpenAccount(COMPONENT_APPID);
        apiComponentToken.setComponent_verify_ticket(entity.getTicket());
        String componentAccessToken = JwThirdAPI.getAccessToken(apiComponentToken);
        //过期重新获取
        String authorizerAppid = "wx39cd0a0d3bac11ea";
        String userName = "gh_0dedd6e60555";
        String authorizerRefreshToken = SpeedStorage.load("authorizer_refresh_token" + authorizerAppid, String.class);

        ApiAuthorizerToken apiAuthorizerToken = new ApiAuthorizerToken();
        apiAuthorizerToken.setAuthorizer_appid(authorizerAppid);
        apiAuthorizerToken.setAuthorizer_refresh_token(authorizerRefreshToken);
        apiAuthorizerToken.setComponent_appid(COMPONENT_APPID);

        ApiAuthorizerTokenRet apiAuthorizerTokenRet = JwThirdApix.apiAuthorizerToken(apiAuthorizerToken, componentAccessToken);

        authorizerRefreshToken = apiAuthorizerTokenRet.getAuthorizer_refresh_token();
        String authorizerAccessToken = apiAuthorizerTokenRet.getAuthorizer_access_token();

        SpeedStorage.save("authorizer_access_token" + userName, authorizerAccessToken);
        SpeedStorage.save("authorizer_refresh_token" + authorizerAppid, authorizerRefreshToken);
        logger.info("微信第三方平台---------2个小时内要重新获取-----------authorizer_access_token=" + authorizerAccessToken);
        logger.info("微信第三方平台---------2个小时内要重新获取-----------authorizer_refresh_token=" + authorizerRefreshToken);
        // 输出响应的内容。
        output(response, "success");
    }

    /**
     * 处理授权事件的推送
     *
     * @param request
     * @throws IOException
     * @throws AesException
     * @throws DocumentException
     */
    public void processAuthorizeEvent(HttpServletRequest request) throws IOException, DocumentException, AesException {
        String nonce = request.getParameter("nonce");
        String timestamp = request.getParameter("timestamp");
        String signature = request.getParameter("signature");
        String msgSignature = request.getParameter("msg_signature");

        if (!StringUtils.isNotBlank(msgSignature)) {
            // 微信推送给第三方开放平台的消息一定是加过密的，无消息加密无法解密消息
            return;
        }
        //true
        boolean isValid = checkSignature(COMPONENT_TOKEN, signature, timestamp, nonce);
        if (isValid) {
            StringBuilder sb = new StringBuilder();
            BufferedReader in = request.getReader();
            String line;
            while ((line = in.readLine()) != null) {
                sb.append(line);
            }
            String xml = sb.toString();
            logger.info("第三方平台全网发布-----------------------原始 Xml=" + xml);
            /**<xml>
             <AppId><![CDATA[wxc92172aa9f766406]]></AppId>
             <Encrypt><![CDATA[Pv2cSqldSQTISd34DsLGnGhklzvPRdrfm7lr30IxIEVizNrK1PXellE03PbuCas/Mo0k6e7f6RLJWD7hnYEcVLRMj1mplzlP2vDW/wwgB++p7BLesMcKv2ZZ/spKVALy5GJ6tQN5xqmeWMWQCTgOusELHBGcImIlZqlQkBZ79UqxGIMIeVlMIFvfalTb+ywK63e+lHbIV7oOS5WFKpsEEeShrmQjQK7JtAl51giEw4RF2vwgs5lg42DtojG2hnOtNv29aq8EXiDVb7e1mXtLwd8DD44pJ5ewpY4jf4REkArW/iqwr3isdJIDsVQbNyH9sJKU9V27r+cNzSCDpTEsa4OckQ4dLW9D36zDH0hhHTVtREIQCSMX9h7bwFNfWHFLzZ7WB38+6WGhplhB7gSrcSKGwI5F+dbUsoVRfjSqSK11eqxgQuJyrKQzUGq5b+dxqxNY/zBaxWIGv3VuAiOlkfmbQVrbnUBBTVROtdWy1c639uuJxaUfwEnzpxPOaeiYNRhvuSYw5omGUmL1IUKpkmk4ST+h9pO58M61raDYkzKuueB4QWjD4Bjq3AIyznyOZBA0vPj7YrFrMbRxtt+ESsi2qrj2Hg8VsmGCBocpTAhtXsFw+IrK1qN3qpd75Chqb7lLpSVGVJCZhT/3hvLhmkWXK5k43y4p+aM4W7xRY3ZCBIWqgTVFpfKz+IhN13tUd7lU/v7CtPm+Nvp0ZpUecV7XMC/QAZrzYqBkiGv0rmgSL1XXbCMUMaUFd/C2dEq7xHScm8yA8Y2vp3d15olrjgMbb/FnQNtaYPw46yHX2Mc=]]></Encrypt>
             </xml>*/
            /**<xml>
             <AppId><![CDATA[wxc92172aa9f766406]]></AppId>
             <Encrypt><![CDATA[zhzV3pQ3MBYd5UoD6aO1A0u8tWvjTknDTBrAIMZqwyTc2mYAn4qlggu/Q3/ekf0kG80q8oYrTgBdt+kI5EsQFhER0FcJXLF/g/RDFs4vFuPnkVB90uSBgs1RBYdPS0IDsHKzucgvx8yOjw1Ah17X1AnYPJCLrjhYNFCL2yNOsd1cxwP6Kxlisg/gWy0J0Maah4e/Hml0UVbezgF2KjYn3woH3Gzt2B+GWkX8jqTd591Zb1HZenEGmu24xEaKCWa2KjUtVixMAw0j98ZM3qDZqxkY+vFppZ+mcywsIaYIFE9rpGGQcu74+I9HLoXwXF1bUqAOtEetueYvWV/jS0huPg==]]></Encrypt>
             </xml>*/

            // 第三方平台组件加密密钥
            String encodingAesKey = COMPONENT_ENCODINGAESKEY;
            // 此时加密的xml数据中ToUserName是非加密的，解析xml获取即可
            String appId = getAuthorizerAppidFromXml(xml);
            logger.info("第三方平台全网发布-------------appid----------getAuthorizerAppidFromXml(xml)-----------appId=" + appId);
            //第三方平台全网发布-------------appid----------getAuthorizerAppidFromXml(xml)-----------appId=wxc92172aa9f766406
            //第三方平台全网发布-------------appid----------getAuthorizerAppidFromXml(xml)-----------appId=null
            WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, encodingAesKey, COMPONENT_APPID);
            xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);
            logger.info("第三方平台全网发布-----------------------解密后 Xml=" + xml);
            /**授权？
             <xml><AppId><![CDATA[wxc92172aa9f766406]]></AppId>
             <CreateTime>1515212788</CreateTime>
             <InfoType><![CDATA[authorized]]></InfoType>
             <AuthorizerAppid><![CDATA[wx570bc396a51b8ff8]]></AuthorizerAppid>
             <AuthorizationCode><![CDATA[queryauthcode@@@FRAb2PoTqAqmpm9qU8Z_CgLHhududFLz-soKXGCH1Rte8S3cg1q9lNI8iAuBmJk5enkwz3UflaWpeNexYxpv6w]]></AuthorizationCode>
             <AuthorizationCodeExpiredTime><![CDATA[1515216388]]></AuthorizationCodeExpiredTime>
             <PreAuthCode><![CDATA[preauthcode@@@5qNY23s4lLrOG_Y79foTralAlprBFk9NTZn1MXxmlx8RMm-pReELEszb8Jmcb_Zy]]></PreAuthCode>
             </xml>
             */
            /**取消授权？<xml><AppId><![CDATA[wxc92172aa9f766406]]></AppId>
             <CreateTime>1515210966</CreateTime>
             <InfoType><![CDATA[unauthorized]]></InfoType>
             <AuthorizerAppid><![CDATA[wx570bc396a51b8ff8]]></AuthorizerAppid>
             </xml>*/
            /**十分钟
             <xml><AppId><![CDATA[wxc92172aa9f766406]]></AppId>
             <CreateTime>1515231578</CreateTime>
             <InfoType><![CDATA[component_verify_ticket]]></InfoType>
             <ComponentVerifyTicket><![CDATA[ticket@@@9XW2Woloqlgj1w5MODv1hmVjGsYQZ-cWznUV0JJhffSnXiJN_GwUUaTB23R2yysEscPTzppCMxLRFf9nhlUTaw]]></ComponentVerifyTicket>
             </xml>
             */
            processAuthorizationEvent(xml);
        }
    }

    /**
     * 判断是否加密
     *
     * @param token
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {

        System.out.println("###token:" + token + ";signature:" + signature + ";timestamp:" + timestamp + "nonce:" + nonce);
        //###token:umk1234567890123456789012345678901234567890;signature:961b3641132360ecb334d049e62b7a4310398b9e;timestamp:1515212788nonce:55386538
        //###token:umk1234567890123456789012345678901234567890;signature:bafdd30c1354cc49f4375e95e6cb1713def6ea68;timestamp:1515210966nonce:1562891409

        boolean flag = false;
        if (signature != null && !"".equals(signature) && timestamp != null && !"".equals(timestamp) && nonce != null && !"".equals(nonce)) {
            String sha1 = "";
            String[] ss = new String[]{token, timestamp, nonce};
            Arrays.sort(ss);
            for (String s : ss) {
                sha1 += s;
            }

            sha1 = AddSha1.sha1(sha1);

            if (sha1.equals(signature)) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 获取授权的Appid
     *
     * @param xml
     * @return
     */
    String getAuthorizerAppidFromXml(String xml) {
        Document doc;
        try {
            doc = DocumentHelper.parseText(xml);
            Element rootElt = doc.getRootElement();
            String appId = rootElt.elementText("AppId");
            return appId;
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存Ticket
     *
     * @param xml
     */
    void processAuthorizationEvent(String xml) {
        Document doc;
        try {
            doc = DocumentHelper.parseText(xml);
            Element rootElt = doc.getRootElement();
            String ticket = rootElt.elementText("ComponentVerifyTicket");
            //开放平台id
            String appid = rootElt.elementText("AppId");
            if (OconvertUtils.isNotEmpty(ticket)) {
                logger.info("8、推送component_verify_ticket协议-----------ticket = " + ticket);
                WeixinOpenAccountEntity entity = getWeixinOpenAccount(appid);
                entity = entity == null ? new WeixinOpenAccountEntity() : entity;
                entity.setTicket(ticket);
                entity.setAppid(appid);
                //TODO Wmdz
                SpeedStorage.save("WeixinOpenAccountEntity" + appid, entity);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取授权账号信息
     *
     * @param appid
     * @return
     */
    WeixinOpenAccountEntity getWeixinOpenAccount(String appid) {
        //TODO Wmdz
        WeixinOpenAccountEntity entity = SpeedStorage.load("WeixinOpenAccountEntity" + appid, WeixinOpenAccountEntity.class);
        return entity;
    }

    /**
     * 接收普通文本消息
     * 第二步
     *
     * @param request
     * @param response
     * @throws IOException
     * @throws AesException
     * @throws DocumentException
     */
    @RequestMapping(value = "{appid}/callback")
    public void acceptMessageAndEvent(HttpServletRequest request, HttpServletResponse response, @PathVariable String appid) throws IOException, AesException, DocumentException, WexinReqException {
        String msgSignature = request.getParameter("msg_signature");
        logger.info("第三方平台全网发布-------------{appid}/callback-----------验证开始。。。。appid = " + appid + " , msg_signature=" + msgSignature);
        //第三方平台全网发布-------------{appid}/callback-----------验证开始。。。。msg_signature=0c31fbbb50a135c1cc694cefc7ce800261c691f8
        //第三方平台全网发布-------------{appid}/callback-----------验证开始。。。。msg_signature=9f7d662d6bafb9aee211917a6cc89a05ea3af023
        //第三方平台全网发布-------------{appid}/callback-----------验证开始。。。。msg_signature=1ee10c15b19265d70d09780e0219251f9ab5211b

        if (!StringUtils.isNotBlank(msgSignature)) {
            return;// 微信推送给第三方开放平台的消息一定是加过密的，无消息加密无法解密消息
        }
        StringBuilder sb = new StringBuilder();
        BufferedReader in = request.getReader();
        String line;
        while ((line = in.readLine()) != null) {
            sb.append(line);
        }
        in.close();

        String xml = sb.toString();
        Document doc = DocumentHelper.parseText(xml);
        Element rootElt = doc.getRootElement();
        String toUserName = rootElt.elementText("ToUserName");

        logger.info("xml=" + xml);
        //微信全网测试账号
        logger.info("全网发布接入检测消息反馈开始---------------appid=" + appid + "------------------------toUserName=" + toUserName);
        //全网发布接入检测消息反馈开始---------------APPID=------------------------toUserName=gh_3c884a361561
        //全网发布接入检测消息反馈开始---------------APPID=------------------------toUserName=gh_3c884a361561
        //全网发布接入检测消息反馈开始---------------APPID=------------------------toUserName=gh_3c884a361561
        checkWeixinAllNetworkCheck(request, response, xml);
    }

    public void checkWeixinAllNetworkCheck(HttpServletRequest request, HttpServletResponse response, String xml) throws DocumentException, IOException, AesException, WexinReqException {
        String nonce = request.getParameter("nonce");
        String timestamp = request.getParameter("timestamp");
        String msgSignature = request.getParameter("msg_signature");

        WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
        xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);

        Document doc = DocumentHelper.parseText(xml);
        Element rootElt = doc.getRootElement();
        String msgType = rootElt.elementText("MsgType");
        String toUserName = rootElt.elementText("ToUserName");
        String fromUserName = rootElt.elementText("FromUserName");

        logger.info("---全网发布接入检测--step.1-----------msgType=" + msgType + "-----------------toUserName=" + toUserName + "-----------------fromUserName=" + fromUserName);
        //---全网发布接入检测--step.1-----------msgType=text-----------------toUserName=gh_3c884a361561-----------------fromUserName=ozy4qt5QUADNXORxCVipKMV9dss0
        //---全网发布接入检测--step.1-----------msgType=text-----------------toUserName=gh_3c884a361561-----------------fromUserName=ozy4qt5QUADNXORxCVipKMV9dss0
        //---全网发布接入检测--step.1-----------msgType=event-----------------toUserName=gh_3c884a361561-----------------fromUserName=ozy4qt5QUADNXORxCVipKMV9dss0
        logger.info("---全网发布接入检测--step.2-----------xml=" + xml);
        //---全网发布接入检测--step.2-----------xml=
        /**<xml><ToUserName><![CDATA[gh_3c884a361561]]></ToUserName>
         <FromUserName><![CDATA[ozy4qt5QUADNXORxCVipKMV9dss0]]></FromUserName>
         <CreateTime>1515210940</CreateTime>
         <MsgType><![CDATA[text]]></MsgType>
         <Content><![CDATA[QUERY_AUTH_CODE:queryauthcode@@@pyO9K-FF4VjKKeBmCIfofkcWxJ10tSlydAM6D4VTm-KdTg2lzHw7I24U2figvamgRX2rM784XsyspmRfp5HP8Q]]></Content>
         <MsgId>6507781434248417810</MsgId>
         </xml>*/
        /**<xml><ToUserName><![CDATA[gh_3c884a361561]]></ToUserName>
         <FromUserName><![CDATA[ozy4qt5QUADNXORxCVipKMV9dss0]]></FromUserName>
         <CreateTime>1515210950</CreateTime>
         <MsgType><![CDATA[text]]></MsgType>
         <Content><![CDATA[TESTCOMPONENT_MSG_TYPE_TEXT]]></Content>
         <MsgId>6507781477198090771</MsgId>
         </xml>*/
        /**<xml><ToUserName><![CDATA[gh_3c884a361561]]></ToUserName>
         <FromUserName><![CDATA[ozy4qt5QUADNXORxCVipKMV9dss0]]></FromUserName>
         <CreateTime>1515210959</CreateTime>
         <MsgType><![CDATA[event]]></MsgType>
         <Event><![CDATA[LOCATION]]></Event>
         <Latitude>111.000000</Latitude>
         <Longitude>222.000000</Longitude>
         <Precision>333.000000</Precision>
         </xml>*/
        if (EVENT_STRING.equals(msgType)) {
            logger.info("---全网发布接入检测--step.3-----------事件消息--------");
            //第三次
            //---全网发布接入检测--step.3-----------事件消息--------

            String event = rootElt.elementText("Event");
            replyEventMessage(request, response, event, toUserName, fromUserName);
        } else if (TEXT_STRING.equals(msgType)) {
            logger.info("---全网发布接入检测--step.3-----------文本消息--------");
            //第一次 第二次
            // --全网发布接入检测--step.3-----------文本消息--------
            // ---全网发布接入检测--step.3-----------文本消息--------

            String content = rootElt.elementText("Content");
            processTextMessage(request, response, content, toUserName, fromUserName);

            //TODO Wmdz
            //文本消息处理存入数据库
            /**<xml><ToUserName><![CDATA[gh_0dedd6e60555]]></ToUserName>
             <FromUserName><![CDATA[oEl-4uETCGjpmbYPmL1vwG7JOW4Q]]></FromUserName>
             <CreateTime>1515226271</CreateTime>
             <MsgType><![CDATA[text]]></MsgType>
             <Content><![CDATA[测试开放平台文字]]></Content>
             <MsgId>6507847280413347084</MsgId>
             </xml>*/
            String toUserName1 = rootElt.elementText("ToUserName");
            String fromUserName1 = rootElt.elementText("FromUserName");
            String createTime = rootElt.elementText("CreateTime");
            String msgType1 = rootElt.elementText("MsgType");
            String content1 = rootElt.elementText("Content");
            String msgId = rootElt.elementText("MsgId");
            String msgTxtContent = content1;
            Date msgTime = new Date(Long.parseLong(createTime) * 1000);
            //0、text 1、语音 2、图片 3、位置
            Integer msgContentType = 0;
            //用户id 这里需要绑定微信用户id和平台用户id
            Long userId = 3L;
            //电台id 这里需要绑定公众号appid或者公众号原始id与电台id绑定
            Long rsId = 1L;
            String msgAttachmentAddr = "";
            //语音长度
            Integer radioLen = 0;

            saveMsgText(toUserName1, fromUserName1, msgTxtContent, msgTime, msgContentType, userId, rsId, radioLen);


        } else if (IMAGE_STRING.equals(msgType)) {
            /**<xml><ToUserName><![CDATA[gh_0dedd6e60555]]></ToUserName>
             <FromUserName><![CDATA[oEl-4uETCGjpmbYPmL1vwG7JOW4Q]]></FromUserName>
             <CreateTime>1515226283</CreateTime>
             <MsgType><![CDATA[image]]></MsgType>
             <PicUrl><![CDATA[http://mmbiz.qpic.cn/mmbiz_jpg/ibQHT1qeJjncwnhKSZ1Gyib4g9MjAFD9ibJOxhyf9y2JxfQyZHjXaCOj2Ioue9tEByD0PKXABVSeZo0licial0qIsibA/0]]></PicUrl>
             <MsgId>6507847331952954638</MsgId>
             <MediaId><![CDATA[7qvWGrugizJCCkrwVlAEYvum5FefaIwqAO3rqmrGt3mdHA548M9yZ7kBNbnrtmnx]]></MediaId>
             </xml>*/
            String toUserName1 = rootElt.elementText("ToUserName");
            String fromUserName1 = rootElt.elementText("FromUserName");
            String createTime = rootElt.elementText("CreateTime");
            String msgType1 = rootElt.elementText("MsgType");
            String picUrl = rootElt.elementText("PicUrl");
            String msgId = rootElt.elementText("MsgId");
            String mediaId = rootElt.elementText("MediaId");
            String msgTxtContent = picUrl;
            Date msgTime = new Date(Long.parseLong(createTime) * 1000);
            //0、text 1、语音 2、图片 3、位置
            Integer msgContentType = 2;
            //用户id 这里需要绑定微信用户id和平台用户id
            Long userId = 3L;
            //电台id 这里需要绑定公众号appid或者公众号原始id与电台id绑定
            Long rsId = 1L;
            String msgAttachmentAddr = "";
            //语音长度
            Integer radioLen = 0;
            saveMsgText(toUserName1, fromUserName1, msgTxtContent, msgTime, msgContentType, userId, rsId, radioLen);
        } else if (LOCATION_STRING.equals(msgType)) {
            /**<xml><ToUserName><![CDATA[gh_0dedd6e60555]]></ToUserName>
             <FromUserName><![CDATA[oEl-4uETCGjpmbYPmL1vwG7JOW4Q]]></FromUserName>
             <CreateTime>1515226314</CreateTime>
             <MsgType><![CDATA[location]]></MsgType>
             <Location_X>43.846607</Location_X>
             <Location_Y>87.483608</Location_Y>
             <Scale>15</Scale>
             <Label><![CDATA[乌鲁木齐市新疆软件园(乌市喀纳斯湖北路455号)]]></Label>
             <MsgId>6507847465096940822</MsgId>
             </xml>
             */
            String toUserName1 = rootElt.elementText("ToUserName");
            String fromUserName1 = rootElt.elementText("FromUserName");
            String createTime = rootElt.elementText("CreateTime");
            String msgType1 = rootElt.elementText("MsgType");
            String locationX = rootElt.elementText("Location_X");
            String locationY = rootElt.elementText("Location_Y");
            String scale = rootElt.elementText("Scale");
            String label = rootElt.elementText("Label");
            String msgId = rootElt.elementText("MsgId");
            String msgTxtContent = label;
            Date msgTime = new Date(Long.parseLong(createTime) * 1000);
            //0、text 1、语音 2、图片 3、位置
            Integer msgContentType = 3;
            //用户id 这里需要绑定微信用户id和平台用户id
            Long userId = 3L;
            //电台id 这里需要绑定公众号appid或者公众号原始id与电台id绑定
            Long rsId = 1L;
            String msgAttachmentAddr = "";
            //语音长度
            Integer radioLen = 0;
            String positionCoor = locationX + "," + locationY;
            saveMsgLocation(toUserName1, fromUserName1, msgTxtContent, msgTime, msgContentType, userId, rsId, radioLen, positionCoor);
        } else if (VOICE_STRING.equals(msgType)) {
            /**<xml><ToUserName><![CDATA[gh_0dedd6e60555]]></ToUserName>
             <FromUserName><![CDATA[oEl-4uETCGjpmbYPmL1vwG7JOW4Q]]></FromUserName>
             <CreateTime>1515226440</CreateTime>
             <MsgType><![CDATA[voice]]></MsgType>
             <MediaId><![CDATA[U6x6vej7BbNxNFzjvlGOk3mQ8pqgcdr2h4lUIkjgltpTNbxH7-IfDxyGbyF4fXL0]]></MediaId>
             <Format><![CDATA[amr]]></Format>
             <MsgId>6507848005834506240</MsgId>
             <Recognition><![CDATA[我啊！]]></Recognition>
             </xml>
             */
            String toUserName1 = rootElt.elementText("ToUserName");
            String fromUserName1 = rootElt.elementText("FromUserName");
            String createTime = rootElt.elementText("CreateTime");
            String msgType1 = rootElt.elementText("MsgType");
            String mediaId = rootElt.elementText("MediaId");
            String format = rootElt.elementText("Format");
            String scale = rootElt.elementText("Scale");
            String msgId = rootElt.elementText("MsgId");
            String recognition = rootElt.elementText("Recognition");
            String msgTxtContent = recognition;
            Date msgTime = new Date(Long.parseLong(createTime) * 1000);
            //0、text 1、语音 2、图片 3、位置
            Integer msgContentType = 1;
            //用户id 这里需要绑定微信用户id和平台用户id
            Long userId = 3L;
            //电台id 这里需要绑定公众号appid或者公众号原始id与电台id绑定
            Long rsId = 1L;
            String msgAttachmentAddr = "";
            //语音长度
            Integer radioLen = 0;
            saveMsgText(toUserName1, fromUserName1, msgTxtContent, msgTime, msgContentType, userId, rsId, radioLen);
        }
        //TODO Wmdz 有待继续扩展 其他消息类型的接收
    }

    private void saveMsgText(String toUserName, String fromUserName, String msgTxtContent, Date msgTime, Integer msgContentType, Long userId, Long rsId, Integer radioLen) throws WexinReqException {
        String msgAttachmentAddr;//https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
        String authorizerAccessToken = SpeedStorage.load("authorizer_access_token" + toUserName, String.class);
        String accessToken = authorizerAccessToken;
        String openid = fromUserName;
        Wxuser wxuser = JwUserAPI.getWxuser(accessToken, openid);
        logger.info(wxuser);
        /**
         {
         "country": "百慕大",
         "subscribe": 1,
         "city": "",
         "openid": "oEl-4uETCGjpmbYPmL1vwG7JOW4Q",
         "tagid_list": [],
         "sex": 1,
         "groupid": 0,
         "language": "zh_CN",
         "remark": "",
         "subscribe_time": 1397449973,
         "province": "",
         "nickname": "Winnid",
         "headimgurl": "http://wx.qlogo.cn/mmopen/PiajxSqBRaEI7F60cicOjHKdYAn2icukQDu74rNSP6ky8oebMxe954EEnLpZGia4tFpQjR4uQ2KClyVjZK1icwyBnzg/0"
         }
        */
        Map<String, String> wechatData = new HashMap<>();
        wechatData.put("nickname", wxuser.getNickname());
        wechatData.put("openid", wxuser.getOpenid());
        wechatData.put("unionid", wxuser.getUnionid());
        //TODO appid 没有来源
        wechatData.put("appid", "");
        wechatData.put("username", toUserName);
        msgAttachmentAddr = SpeedStorage.gson.toJson(wechatData);


        //msgWebService.saveFromWechat(msgTxtContent, msgTime, msgContentType, userId, rsId, msgAttachmentAddr, radioLen, "");
    }
    private void saveMsgLocation(String toUserName, String fromUserName, String msgTxtContent, Date msgTime, Integer msgContentType, Long userId, Long rsId, Integer radioLen, String positionCoor) throws WexinReqException {
        String msgAttachmentAddr;//https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
        String authorizerAccessToken = SpeedStorage.load("authorizer_access_token" + toUserName, String.class);
        String accessToken = authorizerAccessToken;
        String openid = fromUserName;
        Wxuser wxuser = JwUserAPI.getWxuser(accessToken, openid);
        logger.info(wxuser);
        Map<String, String> wechatData = new HashMap<>();
        wechatData.put("nickname", wxuser.getNickname());
        wechatData.put("openid", wxuser.getOpenid());
        wechatData.put("unionid", wxuser.getUnionid());
        //TODO appid 没有来源
        wechatData.put("appid", "");
        wechatData.put("username", toUserName);
        msgAttachmentAddr = SpeedStorage.gson.toJson(wechatData);
    }


    public void replyEventMessage(HttpServletRequest request, HttpServletResponse response, String event, String toUserName, String fromUserName) throws DocumentException, IOException {
        String content = event + "from_callback";
        logger.info("---全网发布接入检测------step.4-------事件回复消息  content=" + content + "   toUserName=" + toUserName + "   fromUserName=" + fromUserName);
        //---全网发布接入检测------step.4-------事件回复消息  content=LOCATIONfrom_callback   toUserName=gh_3c884a361561   fromUserName=ozy4qt5QUADNXORxCVipKMV9dss0
        replyTextMessage(request, response, content, toUserName, fromUserName);
    }

    public void processTextMessage(HttpServletRequest request, HttpServletResponse response, String content, String toUserName, String fromUserName) throws IOException, DocumentException {
        logger.info("processTextMessage :"  + content);
        //processTextMessage :QUERY_AUTH_CODE:queryauthcode@@@FRAb2PoTqAqmpm9qU8Z_CgLHhududFLz-soKXGCH1Rte8S3cg1q9lNI8iAuBmJk5enkwz3UflaWpeNexYxpv6w

        if (TESTCOMPONENT_MSG_TYPE_TEXT_STRING.equals(content)) {
            String returnContent = content + "_callback";
            replyTextMessage(request, response, returnContent, toUserName, fromUserName);
        } else if (StringUtils.startsWithIgnoreCase(content, QUERY_AUTH_CODE_STRING)) {
            output(response, "");
            //接下来客服API再回复一次消息
            replyApiTextMessage(request, response, content.split(":")[1], fromUserName);
        }
    }

    /**
     * 回复微信服务器"文本消息"
     *
     * @param request
     * @param response
     * @param content
     * @param toUserName
     * @param fromUserName
     * @throws DocumentException
     * @throws IOException
     */
    public void replyTextMessage(HttpServletRequest request, HttpServletResponse response, String content, String toUserName, String fromUserName) throws DocumentException, IOException {
        Long createTime = Calendar.getInstance().getTimeInMillis() / 1000;
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        sb.append("<ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>");
        sb.append("<FromUserName><![CDATA[" + toUserName + "]]></FromUserName>");
        sb.append("<CreateTime>" + createTime + "</CreateTime>");
        sb.append("<MsgType><![CDATA[text]]></MsgType>");
        sb.append("<Content><![CDATA[" + content + "]]></Content>");
        sb.append("</xml>");
        String replyMsg = sb.toString();

        String returnvaleue = "";
        try {
            WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
            returnvaleue = pc.encryptMsg(replyMsg, createTime.toString(), "easemob");
            System.out.println("------------------加密后的返回内容 returnvaleue： "+returnvaleue);
        } catch (AesException e) {
            e.printStackTrace();
        }
        output(response, returnvaleue);
    }

    public void replyApiTextMessage(HttpServletRequest request, HttpServletResponse response, String auth_code, String fromUserName) throws DocumentException, IOException {
        String authorizationCode = auth_code;
        // 得到微信授权成功的消息后，应该立刻进行处理！！相关信息只会在首次授权的时候推送过来
        System.out.println("------step.1----使用客服消息接口回复粉丝----逻辑开始-------------------------");
        try {
            ApiComponentToken apiComponentToken = new ApiComponentToken();
            apiComponentToken.setComponent_appid(COMPONENT_APPID);
            apiComponentToken.setComponent_appsecret(COMPONENT_APPSECRET);
            WeixinOpenAccountEntity entity = getWeixinOpenAccount(COMPONENT_APPID);
            apiComponentToken.setComponent_verify_ticket(entity.getTicket());
            String componentAccessToken = JwThirdAPI.getAccessToken(apiComponentToken);

            System.out.println("------step.2----使用客服消息接口回复粉丝------- component_access_token = " + componentAccessToken + "---------authorization_code = " + authorizationCode);
            JSONObject authorizationInfoJson = JwThirdAPI.getApiQueryAuthInfo(COMPONENT_APPID, authorizationCode, componentAccessToken);
            System.out.println("------step.3----使用客服消息接口回复粉丝-------------- 获取authorizationInfoJson = " + authorizationInfoJson);
            JSONObject infoJson = authorizationInfoJson.getJSONObject("authorization_info");
            String authorizerAccessToken = infoJson.getString("authorizer_access_token");


            Map<String, Object> obj = new HashMap<String, Object>();
            Map<String, Object> msgMap = new HashMap<String, Object>();
            String msg = auth_code + "_from_api";
            msgMap.put("content", msg);

            obj.put("touser", fromUserName);
            obj.put("msgtype", "text");
            obj.put("text", msgMap);
            JwThirdAPI.sendMessage(obj, authorizerAccessToken);
        } catch (WexinReqException e) {
            e.printStackTrace();
        }

    }

    /**
     * 工具类：回复微信服务器"文本消息"
     *
     * @param response
     * @param returnvaleue
     */
    public void output(HttpServletResponse response, String returnvaleue) {
        try {
            PrintWriter pw = response.getWriter();
            pw.write(returnvaleue);
			System.out.println("****************returnvaleue***************="+returnvaleue);
            pw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 验证是否过期
     *
     * @param accessTokenExpires
     * @return
     */
    boolean isExpired(long accessTokenExpires) {
        return false;
    }

    @RequestMapping(value = "saveSpeedStorage")
    public Object saveSpeedStorage(ModelMap modelMap) throws WexinReqException {

        ApiComponentToken apiComponentToken = new ApiComponentToken();
        apiComponentToken.setComponent_appid(COMPONENT_APPID);
        apiComponentToken.setComponent_appsecret(COMPONENT_APPSECRET);
        WeixinOpenAccountEntity entity = getWeixinOpenAccount(COMPONENT_APPID);
        apiComponentToken.setComponent_verify_ticket(entity.getTicket());
        String componentAccessToken = JwThirdAPI.getAccessToken(apiComponentToken);
        //过期重新获取
        String authorizerAppid = "wx39cd0a0d3bac11ea";
        String userName = "gh_0dedd6e60555";
        String authorizerRefreshToken = SpeedStorage.load("authorizer_refresh_token" + authorizerAppid, String.class);

        ApiAuthorizerToken apiAuthorizerToken = new ApiAuthorizerToken();
        apiAuthorizerToken.setAuthorizer_appid(authorizerAppid);
        apiAuthorizerToken.setAuthorizer_refresh_token(authorizerRefreshToken);
        apiAuthorizerToken.setComponent_appid(COMPONENT_APPID);

        ApiAuthorizerTokenRet apiAuthorizerTokenRet = JwThirdApix.apiAuthorizerToken(apiAuthorizerToken, componentAccessToken);

        authorizerRefreshToken = apiAuthorizerTokenRet.getAuthorizer_refresh_token();
        String authorizerAccessToken = apiAuthorizerTokenRet.getAuthorizer_access_token();

        SpeedStorage.save("authorizer_access_token" + userName, authorizerAccessToken);
        SpeedStorage.save("authorizer_refresh_token" + authorizerAppid, authorizerRefreshToken);
        logger.info("微信第三方平台---------2个小时内要重新获取-----------authorizer_access_token=" + authorizerAccessToken);
        logger.info("微信第三方平台---------2个小时内要重新获取-----------authorizer_refresh_token=" + authorizerRefreshToken);

        Map<String, Object> data = new HashMap<>();
        data.put("data", apiAuthorizerTokenRet);
        return setSuccessModelMap(modelMap, data);
    }
    @RequestMapping(value = "loadSpeedStorage")
    public Object loadSpeedStorage(ModelMap modelMap) throws IOException {
        /*String appid = "wxc92172aa9f766406";
        WeixinOpenAccountEntity entity = getWeixinOpenAccount(appid);
        logger.info(entity.getTicket());*/
        String authorizerAccessToken = SpeedStorage.load("authorizer_access_token" + "gh_0dedd6e60555", String.class);
        logger.info(authorizerAccessToken);

        Map<String, Object> data = new HashMap<>();
        data.put("data", authorizerAccessToken);
        return setSuccessModelMap(modelMap, data);
    }


    public static void main(String[] args) {
        Long createTime = Calendar.getInstance().getTimeInMillis() / 1000;
        String replyMsg = "LOCATIONfrom_callback";

        String returnvaleue = "";
        try {
            WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, COMPONENT_ENCODINGAESKEY, COMPONENT_APPID);
            returnvaleue = pc.encryptMsg(replyMsg, createTime.toString(), "easemob");
            System.out.println(returnvaleue);
        } catch (AesException e) {
            e.printStackTrace();
        }
    }


}